﻿<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<HTML>
<HEAD>
 <META NAME="GENERATOR" CONTENT="SGML-Tools 1.0.9">
 <TITLE>Программа обработки архивов tar.: ФОРМАТ  АРХИВОВ  TAR</TITLE>
 <LINK HREF="tar-10.html" REL=previous>
 <LINK HREF="tar.html#toc11" REL=contents>
</HEAD>
<BODY>
Next
<A HREF="tar-10.html">Previous</A>
<A HREF="tar.html#toc11">Contents</A>
<HR>
<H2><A NAME="s11">11. ФОРМАТ  АРХИВОВ  TAR</A></H2>

<P>
<P>
<P>
<H2><A NAME="ss11.1">11.1 Стандартный формат *</A>
</H2>

<P>
<P>Архивный файл tar содержит серию  записей.  Каждая  запись  содержит
RECORDSIZE  байт. Хотя  этот  формат  имеет  место  при    пользовании
магнитной лентой, часто используются и другие носители.
<P>Каждый  заархивированный  файл  представлен  заглавием,  описывающим
файл, за  которым  может  следовать  какое-то  число  записей,  дающих
содержание файла. В конце архивного файла может быть запись, состоящая
из двоичных нулей, и  маркер  конца  файла.  Разумная  система  должна
записывать нули в конец, но такая запись не предполагается при  чтении
архива.
<P>Записи могут быть разбиты на  блоки  для  физических  операций  I/O.
Каждый  блок  из  n  записей  (где  n  задана    с    помощью    опции
'--block-size=512-размер') записывается  посредством  операции  'write
()'. На магнитных лентах результат этого - отдельная запись на  ленте.
При записывании архива последний блок записей должен  быть  записан  в
полном размере, и его запись должна  состоять  из  одних  нулей.  При
чтении архива разумная система должна иметь дело с архивами, последний
блок которых короче остальных или который содержит ненужную информацию
после нулей.
<P>Заголовок определен в C (см.  ниже).  В  GNU  tar  это  часть  файла
'src/tar.h':
<P>
<PRE>
/* Standard Archive Format - Standard TAR - USTAR.  */

/* Header block on tape.
  Здесь мы используем традиционные  названия  DP.  "block"  -  большая
часть материала I/O. "record" - кусок информации, с которой  мы  имеем
дело. Обычно много "record" помещается в "block". */

#define RECORDSIZE      512
#define NAMSIZ          100
#define TUNMLEN         32
#define TGNMLEN         32
#define SPARSE_EXT_HDR  21
#define SPARSE_IN_HDR   4

struct sparse  {
  char offset[12];
  char numbytes[12];
};

union record {
  char charptr[RECORDSIZE]

  struct header
  {
    char arch_name[NAMSIZ];
    char mode[8];
    char uid[8];
    char gid[8];
    char size[12];
    char mtime[12];
    char chksum[8];
    char linkflag;
    char arch_linkname[NAMSIZ];
    char magic[8];
    char uname[TUNMLEN];
    char gname[TGNMLEN];
    char devmajor[8];
    char devminor[8];

    // Следующие поля были добавлены в GNU и не являются стандартными
    char atime[12];
    char ctime[12];
    char offset[12];
    char longnames[4];

    // Некоторые компиляторы сами вставляют содержимое. Но проще всегда его вставлять!
    char pad;
    struct sparse sp[SPARSE_INHDR];
    char isextended;
    char realsize[12];          // истинный размер разреженного файла
#if 0
    char ending_blanks[12];     // число нулей в конце файла, если любое
#endif
  } header;
  struct extended-header
  {
    struct sparse sp[21];
    char isextended;
  } ext_hdr;
};

/* Поле контрольной суммы  заполняется,  когда  сосчитана  контрольная сумма. */
#define CHKBLANKS " " /* 8 пропусков, не нулей */

/* Поле magic заполняется этим значением, если допустимы  uname  и
gname, отмечающие архив, как в стандарте POSIX (сам GNU не  согласован
с POSIX). */
#define TMAGIC "ustar  "    /* 7 символов и ноль */

/* Поле magic заполняется этим, если это элемент дампа формата GNU.
Но я полагаю, что это теперь неверно. */
#define GNUMAGIC "GNUtar  "    /* 7 символов и ноль */

/* Указательный флаг определяет тип файла. */
#define LF_OLDNORMAL     '\0'      /* нормальный дисковый файл, Unix-совместимый */
#define LF_NORMAL        '0'       /* нормальный дисковый файл */
#define LF_LINK          '1'       /* указатель на предыдущий дампированный файл */
#define LF_SYNLINK       '2'       /* символьный указатель */
#define LF_CHR           '3'       /* символьный специальный файл */
#define LF_BLK           '4'       /* блочный специальный файл */
#define LF_DIR           '5'       /* каталог */
#define LF_FIFO          '6'       /* специальный файл FIFO */
#define LF_CONFIG        '7'       /* непрерывный файл */
/* Дальнейшие типы указателей определены позже */

/* Заметьте, что стандарты допускают только прописные буквы от А до  Z
для расширения, определяющего пользователя. Это значит, что определять
что-нибудь с помощью, например, '8' - плохая идея. */

/* Это элемент каталога,  содержащий  имена  файлов,  которые  были  в
каталоге в то время, когда был сделан дамп. */
#define LF_DUMPDIR     'D'

/*  Идентифицирует  NEXT  файл  на  ленте,  как  имеющий  длинное  имя
указателя. */
#define LF_LONGLINK    'K'

/* Идентифицирует NEXT файл на ленте, как имеющий длинное имя.  */
#define LF_LONGNAME    'L'

/* Это продолжение файла, который начался в другом томе. */
#define LF_MULTIVOL    'M'

/* Для хранения имен файлов, которые занимают более 100 символов. */
#define LF_NAMES       'N'

/* Это для разреженных файлов. */
#define LF_SPARSE      'S'

/* Этот файл - заголовок ленты/тома. Игнорирует его при извлечении. */
#define LF_VOLHDR      'V'

#if 0
/* Следующие два блока #define'ов не используются в GNU tar. */

/*  В  поле  режима  используются  двоичные  разряды  -  значения    в
восьмиричных числах. */
#define TSUID   04000     /* задайте UID при выполнении */
#define TSGID   12000     /* задайте GID при выполнении */
#define TSVTX   01000     /* сохраните текст (бит). */

/* Возможности файлов */
#define TUREAD   00400    /* читать создателю */
#define TUWRITE  00200    /* записывать создателю */
#define TUEXEC   00100    /* выполнять/искать создателю */
#define TGREAD   00040    /* читать группе */
#define TGWRITE  00020    /* записывать группе */
#define TGEXEC   00010    /* выполнять/искать группе */
#define TOREAD   00004    /* читать другим */
#define TOWRITE  00002    /* записывать другим */
#define TOEXEC   00001    /* выполнять/искать другим */

#endif

/* Конец описания Стандартного Формата Архива. */
</PRE>

Все символы в заглавных записях представлены 8-битными  символами  в
локальном  варианте  ASCII. Все поля структуры прилегают друг к другу,
т.е. не  нужно  заполнять  промежутки.  Все  символы  носителя  архива
хранятся смежно.
<P>Байты, представляющие  содержание  файлов  (после  заглавной  записи
каждого файла) никак не транслируются и не ограничивают представленные
символы определенным символьным множеством. В  формате  tar  текстовые
файлы не отличаются  от  двоичных  файлов,  и  трансляция  содержимого
файлов не производится.
<P>name, linkname, magic,  uname  and  gname  -  заканчивающиеся  нулем
символьные строки. Все остальные поля в  ASCII  -  заполняемые  нулями
восьмиричные числа. Каждое числовое поле ширины w содержит  w-2  цифр,
пробел и ноль, за исключением size и mtime, которые не содержат нуля.
<P>Поле field - имя файла, в котором имя  кaталога  предшествует  имени
файла, и они разделены '/'.
<P>Поле field обеспечивает 9 бит, задающих  разрешения  файлам,  и  три
бит для задания режимов Set UID, Set GID и  Save  Text.  Значения  для
этих бит определены выше. Когда требуются специальные  разрешения  для
создания файла с данным режимом, и у пользователя, обновляющего  файлы
в архиве, нет такого разрешения, биты режима, задающие эти специальные
разрешения,  игнорируются.  Режимы,    которые    не    поддерживаются
операционной системой,  обновляющие  файлы  из  архива,  игнорируются.
Неподдерживаемые  режимы  должны  быть  определены  при  создании  или
модификации архива;  разрешение  группы  можно  скопировать  с  других
разрешений.
<P>Поля uid и  gid - численные  идентификаторы  пользователя  и  группы
создателя  файла  соответственно.  Если  операционная    система    не
предполагает таких идентификаторов, эти поля должны игнорироваться.
<P>Поле size - размер файла в байтах; указываемые файлы архивируются  с
помощью поля, заданного как ноль.
<P>Поле mtime - модификационное время файла  во  время,  когда  он  был
заархивирован. Это  представление   ASCII    восьмиричного    значения
последнего времени, когда он был модифицирован, представляемое в целом
числе секунд с 1 января 1970г. 00:00  Координационного  Универсального
Времени.
<P>Поле chksum - представление ASCII восьмиричного числа простой  суммы
всех  байт  заглавной  записи.  Каждый  8-битный  байт   в    заглавии
прибавляется к числу без знака, инициализированному на ноль,  точность
которого  должна  быть  не  меньше  семнадцати  бит.  При   вычислении
контрольной суммы поле chksum рассматривается, как состоящее из  одних
пропусков.
<P>Поле typeflag задает тип заархивированного файла. Если реализация не
рассматривает или разрешает указанный тип, файл извлекается, как  если
бы  он  был  регулярным  файлом.  Если  же  он  рассматривается  и  не
разрешается, tar выдает предостережение на стандартный вывод.
<P>Поля atime и ctime используются в проведении пошаговых резервных
копирований, они сохраняют соответственно время доступа файлов и
последнее измененное время.
<P>offset используется для опции '--multi-volume' ('-M')  при  создании
многотомного архива. offset - число байтов файла,  которые  нам  нужны
для того, чтобы продолжить файл на следующую ленту.
<P>Следующие поля были добавлены для  работы  с  разреженными  файлами.
Файл разрежен, если он  содержит  блоки,  концы  которых  представлены
нулями, т.е. неиспользуемыми данными. Проверить, разрежен  ли  файл  -
значит, посмотреть число блоков, занимаемых файлом и  сравнить  его  с
числом символов файла: если блоков, выделяемых под файл,  меньше,  чем
должно выделяться под файл такого размера, то файл  разреженный.  Этот
метод tar использует для определения разреженного файла, и если  такой
файл найден, он рассматривается отдельно от неразреженных файлов.
<P>Разреженные файлы - часто файлы dbm или других  типов  базы  данных,
которые имеют данные на некоторых местах и  пустоту  в  большей  части
файла. Такие файлы возникают, когда к ним  применяется  'ls  -l',  они
могут содержать очень мало важных данных. Таким образом  нежелательно,
чтобы tar производил резервное копирование этих  файлов,  когда  много
места занято пустыми блоками, что может привести к истощению места  на
диске гораздо раньше, чем надо бы.  Т.ч.  нужно  рассматривать  вопрос
таким образом, чтобы пустые блоки не  записывались  на  ленту.  Вместо
этого на ленту записывается описание разреженного файла: сколько  дыр,
насколько они велики, сколько данных находится  в  конце  дыры.  Таким
образом файлы потенциально занимают намного меньше места на  ленте,  и
когда они  впоследствии извлекаются, это происходит таким  же  образом,
как описано выше. Следующее - описание полей, используемых для  работы
с разреженными файлами:
<P>sp - массив  struct  sparse.  Каждый  struct  sparse  содержит   две
12-символьных строки, которые представлены смещением в файл  и  числом
байтов, подлежащих записи в это смещение.  Смещение  абсолютное  и  не
относится к смещению предыдущего элемента массива.
<P>Заглавие может содержать четыре  struct  sparse  одновременно;  если
нужно больше, они не сохраняются в заглавии.
<P>Флаг isextended задается, когда  нужно  иметь  дело  с  файлом.  Это
значит, что этот флаг  может  быть  установлен  только  при  работе  с
разреженным  файлом,  и  установлен  только  если  описание  файла  не
помещается  на  место,  предназначенное  для  разреженных  структур  в
заглавии. Другими словами, нужен extended_header.
<P>Структура  extended_header  используется  для  разреженных   файлов,
которым нужно больше разреженных структур,  чем  может  поместиться  в
заглавии. Заглавие может содержать четыре таких структуры; если  нужно
больше,  устанавливается  флаг  isextended  и  следующая   запись    -
extended_header.
<P>Каждая структура extended_header содержит массив из  21  разреженной
структуры при  наличии  флага  isextended  у  заглавия.  Для  описания
разреженного файла  может  потребоваться  неопределенное  число  таких
extended_header.
<DL>
<DT><B>LF_NORMAL </B><DD><P>
<DT><B>LF_OLDNORMAL </B><DD><P>Эти флаги представляют регулярный файл. Для совместимости со
старыми версиями tar значение typeflag  LF_OLDNORMAL  должно
рассматриваться как регулярный  файл.  Новые  архивы  должны
создаваться  при  помощи  IF_NORMAL.  Также,  для   обратной
согласованности, tar  рассматривает  регулярные  файлы,  чьи
имена заканчиваются на '/', как каталоги.
<P>
<DT><B>LF_LINK </B><DD><P>Этот флаг представляет  файл,  указывающий  на  другой  файл
любого  типа,  заархивированный  перед  ним.  Такие    файлы
идентифицируются в Unix с  помощью  файлов,  имеющих  то  же
устройство и номер. Указываемое имя задано на поле  linkname
с последним нулем.
<P>
<DT><B>IF_SYMLINK </B><DD><P>Это  представляет  символьный  указатель  на  другой   файл.
Указываемое имя задано на поле linkname с последним нулем.
<P>
<DT><B>LF_CHR </B><DD><P>
<DT><B>LF_BLK </B><DD><P>Представляют  символьные  специальные  файлы    и    блочные
специальные  файлы  соответственно.  В  этом  случае    поля
devmajor и devminor  содержат  номера  большего  и  меньшего
устройств.  Операционная   система    отображает    описания
устройства  в  собственное  локальное  описание  или   может
игнорировать элемент.
<P>
<DT><B>LF_DIR </B><DD><P>Этот флаг задает каталог или  подкаталог.  Имя  каталога  на
поле  name  должно  заканчиваться  '/'.  В  системах,    где
заполнение диска выполняется на основе каталога,  поле  size
содержит максимальное число байт (которые можно  привести  к
ближайшей единице дискового блока), которое может  содержать
каталог. Нулевое поле size не указывает такого  ограничения.
Системы, не предполагающие  такого  ограничения,  игнорируют
поле size.
<P>
<DT><B>LF_FIFO </B><DD><P>Задает специальный файл  FIFO.  Заметьте,  что  архивируется
только существование файла FIFO, а не содержимое.
<P>
<DT><B>LF_CONFIG </B><DD><P>Задает непрерывный файл, который отличается от обыкновенного
тем, что в операционной системе, которая  его  поддерживает,
нет  пропусков.  Операционные  системы,    не    позволяющие
непрерывного  размещения,  рассматривают  этот   файл    как
обыкновенный.
<P>
<DT><B>A...Z </B><DD><P>Зарезервированы для реализаций клиентов.  Некоторые  из  них
используются в модификационном формате GNU (см.ниже).
</DL>

Другие значения зарезервированы для задания  при  будущих  проверках
стандарта P1003 и не должны использоваться программой tar.
<P>Поле magic показывает, что этот архив был выведен в  форматe  P1003.
Если это поле содержит TMAGIC, поля  uname  и  gname  будут  содержать
представление  ASCII  создателя  и  группы    файла    соответственно.
Идентификаторы пользователя и группы используются скорее, чем поля uid
и gid.
<P>
<P>
<H2><A NAME="ss11.2">11.2 Дополнения GNU к формату архива *</A>
</H2>

<P>
<P>Формат GNU использует дополнительные типы файлов для описания  новых
типов файлов архива. Они перечислены ниже.
<DL>
<DT><B>LF_DUMPDIR </B><DD><P>
<DT><B>'D' </B><DD><P>Представляет  каталог  и  список  файлов,  созданный  опцией
'--incremental'.    Поле    size    дает    общий     размер
ассоциированного  списка  файлов.  Каждому    имени    файла
предшествует или 'Y' (этот файл должен быть  в  архиве)  или
'N' (файл - каталог, или не хранится в архиве).  Каждое  имя
файла заканчивается нулем.  Существует  дополнительный  ноль
после последнего имени файла.
<P>
<DT><B>LF_MULTIVOL </B><DD><P>
<DT><B>'M' </B><DD><P>Представляет  файл,  продолжающийся    из    другого    тома
многотомного  архива,    созданного    с    помощью    опции
'--multi-volume'. Начальный тип файла здесь не дается.  Поле
size  дает  максимальный   размер    этого    куска    файла
(предполагается, что том не кончается до тех пор, пока  файл
не записан). Поле offset дает смещение от  начала  файла  до
того места, где начинается эта часть файла.  Таким  образом,
size + offset - то же самое, что начальный размер файла.
<P>
<DT><B>LF_SPARSE </B><DD><P>
<DT><B>'S' </B><DD><P>Этот флаг  показывает,  что  мы  имеем  дело  с  разреженным
файлом. Нужно отметить, что архивирование разреженного файла
требует специальных операций для нахождения дырок  в  файле,
отмечающих  положения  этих  дырок  и    выявляющих    число
байт данных, найденных после дырки.
<P>
<DT><B>LF_VOLHDR </B><DD><P>
<DT><B>'V' </B><DD><P>Этот  тип  файла  используется  для  того,  чтобы   отмечать
заглавие  тома,  которое  было  дано   с    помощью    опции
'--label=архивная_метка'. Поле size - нулевое. Только первый
файл каждого тома архива должен иметь этот тип.
</DL>

У вас могут появиться сложности при  чтении  архива  формата  GNU  в
не-GNU системах, если при этом были использованы опции '--incremental'
('-G'),    '--multi-volume'    ('-M'),    '--sparse'    ('-S')     или
'--label=архивная_метка'.  Обычно,  если  tar  не  использует    поля,
добавленные GNU, в заглавии, другие версии tar могут читать  архив.  В
противном случае программа tar выдает  ошибку,  в  лучшем  случае  это
ошибка контрольной суммы.
<P>
<P>
<H2><A NAME="ss11.3">11.3 Сравнение tar и cpio *</A>
</H2>

<P>
<P>Здесь приведен перечень различий между tar  и  cpio.  Точность  этой
информации еще не проверялась. Написанию  этого  раздела,  в  основном
через обзор 1991 года, способствовали следующие люди:
<UL>
<LI> Бент Бертельсен
<A HREF="mailto:dmdata@login.dkuug.dk">dmdata@login.dkuug.dk</A></LI>
<LI> Давид Хупес         talgras!david</LI>
<LI> Гей Харрис
<A HREF="mailto:guy@auspex.com">guy@auspex.com</A></LI>
<LI> Кай Петцке
<A HREF="mailto:wpp@marie.physic.tu-berlin.de">wpp@marie.physic.tu-berlin.de</A></LI>
<LI> Кристен Нильсен
<A HREF="mailto:dmdata@login.dkuug.dk">dmdata@login.dkuug.dk</A></LI>
<LI> Лесли Майкшелл
<A HREF="mailto:les@chinet.chi.il.us">les@chinet.chi.il.us</A></LI>
</UL>

<P>tar работает с символьными указателями в той форме, что в BSD;  cpio
же  не  имеет  дела  с  символьными  указателями  в  форме  System  V,
предшествовавшей SVR4, и некоторые продавцы добавляли в  свои  системы
символьные указатели, в то же  время  не  давая  cpio  о  них  никакой
информации. Другие делают это, но не тем способом, каким я это делал в
Sun и который был принят AT&amp;T (и который, я думаю, присутствует в том,
что Беркли взял из AT&amp;T и вложил в поздний BSD  -  мне  кажется,  туда
попали мои изменения).
<P>(SYR4 не так хорош с tar; в  основном  его  cpio  может  работать  с
вводом формата tar и записывать его на вывод, и , вероятно, работает с
символьными указателями. Они могут  ничего  не  пытаться  сделать  для
того, чтобы усилить tar.)
<P>cpio работает со специальными файлами, а традиционный tar - нет.
<P>tar произошел из V7, System III, System V и BSD; cpio  -  из  System
III, System V и позднего BSD (4.3 и позже)
<P>Способ  tar  обработки  множественных  указателей  на  файл    может
обрабатывать системы файлов, предполагающие 32-битные номера (так  же,
как система файлов BSD); метод сpio требует от вас  игры  в  некоторые
игры (в его  "двоичный"  формат,  i-числа  и  только  16  бит,  и  его
"мобильный  формат  ASCII",  18  бит;  он  должен  играть  в  игры   с
полем  "идентификатора  системы  файлов"  заглавия  для  того,   чтобы
убедиться, что идентификатор системы файлов / i-число  -  пара  разных
файлов - всегда разные).
<P>При способе tar обработки множественных указателей на файл на  ленту
помещается только одна копия указателя, но  имя,  относящееся  к  этой
копии - единственное, которое вы можете  использовать  для  извлечения
этого файла; cpios тоже кладет только одну копию каждого указателя, но
вы можете извлечь его, используя любое из имен.
<P>&gt; Какой тип контрольной суммы используется, и как ее сосчитать.
<P>О формате tar и cpio см.  руководства.  tar  использует  контрольную
сумму, которая является суммой  всех  байт  заглавия  файла;  cpio  не
использует контрольных сумм.
<P>&gt; Знает ли кто-нибудь, зачем нужно было делать cpio,  когда  уже  был
tar? Сообщите мне, пожалуйста.
<P>cpio впервые появился в PWB/UNIX 1.0; UNIX тогда  не  имел  ни  одной
общедоступной версии tar. Я не  знаю,  была  ли  в  AT&amp;T  какая-нибудь
версия tar или, может быть, люди в AT&amp;T,  создавшие  cpio,  вообще  не
знали о нем.
<P>Если при обновлении на ленте есть повреждения, tar останавливается в
этом месте, а cpio  его  перескакивает  и  пытается  обновить  остаток
файлов.
<P>Основное различие - в синтаксисе команд и формате заглавия.
<P>tar более ориентирован на ленты, и во всем, что  разбито  на  блоки,
начинает работу с границы блока.
<P>&gt; Есть ли какие-нибудь различия в способности обновлять поврежденные
архивы (если их вообще можно восстановить)?
<P>Теоретически это должно быть легче под tar, т.к. разбиение на  блоки
позволяет находить заглавие с помощью некоторых вариаций 'dd skip=nn'.
Однако в современном cpio  и  вариациях  есть  опция  поиска  заглавия
следующего файла  после  ошибки  с  возможностью  ресинхронизации.  Но
программное обеспечение драйверов многих лент не позволяет  продолжать
работу после  ошибки  носителя,  что  является  единственной  причиной
использования синхронизации, если файлы не меняли размеров,  когда  вы
записывали архив.
<P>&gt; Знает ли кто-нибудь, зачем нужно было делать cpio,  когда  уже  был
tar? Сообщите мне, пожалуйста.
<P>Наверно, потому, что он более эффективен с  точки  зрения  носителей
(не разбивая все на блоки и используя только  место,  необходимое  для
заглавия, в то время как  tar  всегда  использует  для  каждого  файла
минимум 512 байт) и может архивировать специальные файлы.
<P>Может, вы захотите ознакомиться  с  доступными  альтернативами.  Это
afio, GNU tar и  pax,  каждый  из  которых  имеет  свои  расширения  с
определенной обратной связью.
<P>Разреженные файлы были определены как разреженные с помощью  tar  (и
их можно легко выявить, а GNU cpio их вообще не читает).
<P>
<P>
<HR>
Next
<A HREF="tar-10.html">Previous</A>
<A HREF="tar.html#toc11">Contents</A>
</BODY>
</HTML>
